package com.cr.dataprotect.provider;

import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.cr.dataprotect.bean.ProviderConfigBean;
import com.cr.dataprotect.common.MyConstants;
import com.cr.dataprotect.config.FieldProvider;
import com.cr.dataprotect.sdk.SecretKeyApi;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.util.HashMap;
import java.util.Map;

/**
 * 抽象提供者类，提供敏感字段配置和默认加密密钥的加载功能。
 *
 * @author ChenRu1
 * @since 2023/12/5
 */
public abstract class AbstractProvider {

    /**
     * 信息配置类，用于加载字段配置。
     */
    @Autowired(required = false)
    private FieldProvider provider;

    @Autowired
    private SecretKeyApi secretKeyApi;


    /**
     * 秘钥映射，键为类型，值为对应的加密密钥。
     */

    public static final String SECRETKEY_ERROR_MSG = "密钥不存在，请检查密钥";


    /**
     * 判断是否有配置字段。
     *
     * @return 如果有配置字段返回 true，否则返回 false
     */
    protected boolean hasProvider() {
        return ObjectUtils.isNotEmpty(provider);
    }

    /**
     * 获取所有的字段配置。
     *
     * @return 字段配置对象，如果没有配置则返回 null
     */
    protected ProviderConfigBean loadAllFieldConfig() {
        if (!hasProvider()) {
            return null;
        }
        return provider.config(null);
    }

    /**
     * 获取配置的默认字段加密秘钥。
     *
     * @param type 加密密钥的类型
     * @return 默认字段加密秘钥，如果未找到则返回 null
     */
    public String loadDefaultSecretKey(String type) {
        return secretKeyApi.loadDefaultSecretKey(type);
    }

    /**
     * 获取密钥
     *
     * @param fieldConfig
     * @param valueClass
     * @param type
     * @return
     */
    protected String getSecretKey(Map<Class, Map<String, Object>> fieldConfig, Class<?> valueClass, String type) {
        String sensitiveSecretKey = loadDefaultSecretKey(type);
        //1.如果配置文件中没有配置密钥，则尝试从配置中获取单独字段的密钥，如果还没有则认为异常
        if (StringUtils.isEmpty(sensitiveSecretKey)) {
            Object secretTypeObj = fieldConfig.get(valueClass).getOrDefault("encryptKeyAlias", null);
            if (ObjectUtils.isNotEmpty(secretTypeObj)) {
                return secretTypeObj.toString();
            } else {
                throw new RuntimeException(SECRETKEY_ERROR_MSG);
            }
        } else {
            return sensitiveSecretKey;
        }
    }

}